package com.example.aesdemo.util;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

/**
 * @description: AES工具类
 * @author: Mr.Hu
 * @create: 2018-05-28 15:34
 **/
@Component
public class AesUtil {
    private Cipher cipher;
    private final int keySize = 128;
    private final int iterationCount = 1000;
    private static final String SECRET_KEY_MODEL = "PBKDF2WithHmacSHA1";
    private static final String CIPHER_MODEL = "AES/CBC/PKCS5Padding";
    public AesUtil(){
        try {
            cipher = Cipher.getInstance(CIPHER_MODEL);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public String encrypt(String salt, String iv, String plaintext) {
        try {
            SecretKey key = generateKey(salt);
            byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, key, iv, plaintext.getBytes("UTF-8"));
            return base64(encrypted);
        }
        catch (UnsupportedEncodingException e) {
            throw fail(e);
        }
    }

    public String decrypt(String salt, String iv, String ciphertext) {
        try {
            SecretKey key = generateKey(salt);
            byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, base64(ciphertext));
            return new String(decrypted, "UTF-8");
        }
        catch (UnsupportedEncodingException e) {
            throw fail(e);
        }
    }

    private byte[] doFinal(int encryptMode, SecretKey key, String iv, byte[] bytes) {
        try {
            cipher.init(encryptMode, key, new IvParameterSpec(hex(iv)));
            return cipher.doFinal(bytes);
        }
        catch (InvalidKeyException
                | InvalidAlgorithmParameterException
                | IllegalBlockSizeException
                | BadPaddingException e) {
            throw fail(e);
        }
    }

    private SecretKey generateKey(String salt) {
        String passphrase = "123456";
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(SECRET_KEY_MODEL);
            KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), hex(salt), iterationCount, keySize);
            SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
            return key;
        }
        catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw fail(e);
        }
    }

    public static String random(int length) {
        byte[] salt = new byte[length];
        new SecureRandom().nextBytes(salt);
        return hex(salt);
    }

    public static String base64(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    public static byte[] base64(String str) {
        return Base64.decodeBase64(str);
    }

    public static String hex(byte[] bytes) {
        return Hex.encodeHexString(bytes);
    }

    public static byte[] hex(String str) {
        try {
            return Hex.decodeHex(str.toCharArray());
        }
        catch (DecoderException e) {
            throw new IllegalStateException(e);
        }
    }

    private IllegalStateException fail(Exception e) {
        return new IllegalStateException(e);
    }


    public static void main(String[] args){
        AesUtil aesUtil = new AesUtil();
        String data = "您好";
        String encrypt = aesUtil.encrypt("697f553d06266099245e30cda323fce5","9834ec515b24c52e2bbe08a63c778ad6",data);
        System.out.println(encrypt);
        System.out.println(aesUtil.decrypt("697f553d06266099245e30cda323fce5","9834ec515b24c52e2bbe08a63c778ad6" , "fNHqjWv+KBHko84U6eXjUfR6f3g+6FNwypmS6KhQC8EA1cSuKOSRX6tJRBmNO/jRi109xJBPH9bCvsyOtX0SnT/CSyJPY4FQrxAVsHGwTEYd15bPGXHb3FUKZ4CDIIXpnEFg60z6IoGI1CzcPkbTwPshGx1LRFkt4yM1KZb/vwk="));
    }
}
